/*
 * Copyright (C) Pietro Pilolli 2010 <pilolli.pietro@gmail.com>
 * 
 * Curtain is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Curtain is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "callbacks.h"
#include "utils.h"


/* The main cairo context; will used to draw the window. */
static cairo_t *cr = (cairo_t *) NULL;

/* The surface will have the same dimension of the screen and will contain the curtain. */
static cairo_surface_t *scaled_surface = (cairo_surface_t *) NULL;

/* Variables where will store the coordinates of the press point. */
static gdouble press_event_x = 0.0;
static gdouble press_event_y = 0.0;

/* These points identify the area with the painted curtain. */
static gdouble min_x = 0.0;
static gdouble max_x = 0.0;
static gdouble min_y = 0.0;
static gdouble max_y = 0.0;

static gint screen_width = 0;
static gint screen_height = 0;

/* The cursor to be displayed. */
static GdkCursor *cursor = (GdkCursor *) NULL;

/* Region use to shape input region. */
static cairo_region_t *shape_reg = (cairo_region_t *) NULL;;

/* Quit the program. */
static void
quit               ()
{
  if (cursor)
    {
      g_object_unref (cursor);
    }
  if (cr)
    {
      cairo_destroy (cr);
    }
  if (scaled_surface)
    {
      cairo_surface_destroy (scaled_surface);
    }
  gtk_main_quit ();
  exit (1);
}


/* Paint the white cross to be clicked in order to close the program. */
static void
paint_cross        ()
{
  if (cr)
    { 
      gint delta = 25;
      gchar *color = "FFFFFFFF";

      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
      cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
      cairo_set_source_color_from_string (cr, color);
      cairo_rectangle (cr, (max_x - delta), min_y, delta, delta);	
      cairo_move_to (cr, (max_x - delta), min_y);
      cairo_line_to (cr, max_x, (min_y + delta));
      cairo_move_to (cr, max_x, min_y);
      cairo_line_to (cr, (max_x - delta), (min_y + delta));
      cairo_stroke (cr);
    }
}


/* Paint the curtain in the window. */
static void
paint_curtain ()
{
  if (cr)
    {
      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_source_surface (cr, scaled_surface, 0, 0);
      cairo_rectangle (cr, min_x, min_y, max_x, max_y);
      cairo_fill (cr);
      cairo_stroke (cr);
    }
  paint_cross ();
}


/* Paint a transparent rectangle on the window. */
static void
paint_transparent_rectangle  (GtkWidget *widget,
                              gdouble x,
                              gdouble y,
                              gdouble width,
                              gdouble height)
{
  if (cr)
    {
      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_source_rgba (cr, 0, 0, 0, 0);
      cairo_rectangle (cr, x, y, width, height);
      cairo_fill (cr);
      cairo_stroke (cr);
    }

  const cairo_rectangle_int_t transparent_rect = {(gint) x,
                                                  (gint) y,
                                                  (gint) width,
                                                  (gint) height };

  cairo_region_t *transparent_reg = cairo_region_create_rectangle (&transparent_rect);

  cairo_region_subtract (shape_reg, transparent_reg);

  gtk_widget_input_shape_combine_region (widget, shape_reg);
  cairo_region_destroy (transparent_reg);
}


/* Destroy window callback. */
G_MODULE_EXPORT gboolean 
destroy (GtkWidget *widget, gpointer data)
{
  quit ();
  return TRUE;
}

/* On configure event. */
G_MODULE_EXPORT gboolean
on_window_configure          (GtkWidget       *widget,
                              GdkEventExpose  *event,
                              gpointer         user_data)
{
  GdkWindowState state = gdk_window_get_state (gtk_widget_get_window (widget));
  gint is_fullscreen = state & GDK_WINDOW_STATE_FULLSCREEN;

  if (!is_fullscreen)
    {
      return FALSE;
    }
  if (! scaled_surface)
    {
      cursor = gdk_cursor_new (GDK_HAND1);
      gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
      cairo_surface_t *surface = cairo_image_surface_create_from_png (CURTAIN_FILE);
      gtk_window_set_opacity (GTK_WINDOW (widget), 1.0);
      screen_width = gdk_screen_width ();
      screen_height = gdk_screen_height ();
      max_x = screen_width;
      max_y = screen_height;
      cr = gdk_cairo_create (gtk_widget_get_window (widget));

      scaled_surface = scale_surface (surface, screen_width, screen_height);
      cairo_surface_destroy (surface);
      paint_curtain ();
    }
  return TRUE;
}

/* Expose event: this occurs when the windows is exposed. */
G_MODULE_EXPORT gboolean 
on_window_expose_event       (GtkWidget  *widget,
                              cairo_t    *cr,
                              gpointer    user_data)
{
  //paint_curtain ();

  return TRUE;
}


/* Destroy callback. */
G_MODULE_EXPORT gboolean 
on_window_destroy_event      (GtkWindow  *self,
                              GdkEvent   *event,
                              gpointer    user_data)
{
  quit ();
  return TRUE;
}


/* On screen changed. */
G_MODULE_EXPORT void
on_window_screen_changed     (GtkWidget  *widget,
                              GdkScreen  *previous_screen,
                              gpointer    user_data)
{
  GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (widget));
  GdkVisual *visual = gdk_screen_get_rgba_visual (screen);
  
  if (visual == NULL)
    {
      visual = gdk_screen_get_system_visual (screen);
    }
  
  gtk_widget_set_visual (widget, visual);
}


/* On press callback. */
G_MODULE_EXPORT gboolean 
on_window_button_press_event      (GtkWidget       *widget,
                                   GdkEventButton  *event,
                                   gpointer         data)
{
  /* only button1 allowed */
  if (event->button != 1)
    {
      return FALSE;
    }

  /* Is inside the close pseudo button. */
  if (((event->x) > (max_x - 25)) &&
      ((event->y) < (min_y + 25)))
    {
      quit ();
    }

  gtk_widget_input_shape_combine_region (widget, NULL);
  const cairo_rectangle_int_t shape_rect = { 0,
                                             0,
                                             gdk_screen_width (),
                                             gdk_screen_height () };

  cairo_region_destroy(shape_reg);
  shape_reg = cairo_region_create_rectangle (&shape_rect);

  press_event_x = event->x;
  press_event_y = event->y;
  return TRUE;
}


/* Release callback. */
G_MODULE_EXPORT gboolean
on_window_button_release_event    (GtkWidget       *widget,
                                   GdkEventButton  *event,
                                   gpointer         data)
{
  gdouble delta_x = fabs (press_event_x-event->x);
  gdouble delta_y = fabs (press_event_y-event->y);

  gint min_curtain_width = 25;
  gint min_curtain_height = 25;

  /* only button1 allowed and ignore null event */
  if ((! event) || (event->button != 1))
    {
      return FALSE;
    }

  if (delta_y <= delta_x)
    {
      /* move on x axis */
      if (event->x >= press_event_x)
        {
          /* Right gesture */
          if ((press_event_x < (max_x + min_x)/2) && ( event->x <= max_x))
            {
              /* sx to the curtain ->| */
              if (event->x > min_x)
                {
                  /* move right of delta_x */
                  //printf("->|\n");
                  min_x = event->x;
                  if (min_x > max_x-min_curtain_width)
                    {
                      min_x = max_x-min_curtain_width;
                    }

                  paint_transparent_rectangle (widget,
                                               0,
                                               0,
                                               min_x,
                                               screen_height);

                  paint_transparent_rectangle (widget,
                                               max_x,
                                               0,
                                               screen_width-max_x,
                                               screen_height);

                }
            }
          else
            {
              /* dx to the curtain |-> */
              if (event->x > max_x)
                {
                  //printf("|->\n");
                  paint_transparent_rectangle (widget,
                                               event->x,
                                               0,
                                               screen_width-event->x,
                                               screen_height);

                  max_x = event->x;
                  if (max_x > screen_width)
                    {
                      max_x = screen_width;
                    }

                  paint_transparent_rectangle (widget,
                                               0,
                                               0,
                                               min_x,
                                               screen_height);

                }
            }
        }
      else
        {
          /* Left gesture */
          if ((press_event_x > (max_x + min_x)/2) && (event->x >= min_x))
            {
              /* dx to curtain |<- */
              if (event->x < max_x)
                {
                  /* move left */
                  //printf("|<-\n");
                  max_x = event->x;	
                  if(max_x-min_x < min_curtain_width)
                    {
                      max_x = min_x + min_curtain_width;
                    }

                  paint_transparent_rectangle (widget, max_x,
                                               0,
                                               (screen_width - max_x),
                                               screen_height);

                  paint_transparent_rectangle (widget,
                                               0,
                                               0,
                                               min_x,
                                               screen_height);

                }
            }
          else
            {
              /* sx to curtain <-| */
              if (event->x < min_x)
                {
                  //printf(" <-|\n");

                  paint_transparent_rectangle (widget,
                                               0,
                                               0,
                                               event->x,
                                               screen_height);

                  min_x = event->x;	
                  if ((max_x - min_x) < min_curtain_width)
                    {
                      max_x = min_x + min_curtain_width;
                    }

                  paint_transparent_rectangle (widget,
                                               max_x,
                                               0,
                                               (screen_width - max_x),
                                               screen_height);

                }
            }
        }	
      if (min_y > 0)
        {

          paint_transparent_rectangle (widget,
                                       0,
                                       0,
                                       screen_width,
                                       min_y);

        }
      if (max_y < screen_height)
        {

          paint_transparent_rectangle (widget,
                                       0,
                                       max_y,
                                       screen_width,
                                       (screen_height - max_y));

        }
    }
  else
    {
      /* move on y axis */
      if (event->y >= press_event_y)
        {
          /* down gesture */
          if ((press_event_y < (max_y + min_y)/2) && (event->y <= max_y))
            {
              if (event->y > min_y)
                {
                  /* up half */
                  min_y = event->y;
                  if (min_y > (max_y - min_curtain_height))
                    {
                      min_y = max_y - min_curtain_height;
                    }

                  paint_transparent_rectangle (widget,
                                               0,
                                               0,
                                               screen_width,
                                               min_y);

                  paint_transparent_rectangle (widget,
                                               0,
                                               max_y,
                                               screen_width,
                                               (screen_height - max_y));

                }
            }
          else
            {
              if (event->y > max_y)
                {
                  /* down half */

                  paint_transparent_rectangle (widget,
                                               0,
                                               event->y,
                                               screen_width,
                                               (screen_height - event->y));

                  max_y = event->y;
                  if (max_y > screen_height)
                    {
                      max_y = screen_height;
                    }

                  paint_transparent_rectangle (widget,
                                               0,
                                               0,
                                               screen_width, min_y);

                }
            }
        }
      else
        {
          /* up gesture */
          if ((press_event_y < (max_y + min_y)/2) || (event->y < min_y))
            {
              if (event->y < min_y)
                {
                  /* up half */
                  //printf("down gesture in first half\n");
                  min_y = event->y;
                  if (min_y > (max_y - min_curtain_height))
                    {
                      min_y = max_y - min_curtain_height;
                    }

                  paint_transparent_rectangle (widget,
                                               0,
                                               0,
                                               screen_width, min_y);

                  paint_transparent_rectangle (widget,
                                               0,
                                               max_y,
                                               screen_width,
                                               screen_height - max_y);

                }
            }
          else
            {
              if (event->y < max_y)
                {
                  /* down half */
                  //printf("down gesture in second half\n");
                  max_y = event->y;
                  if((max_y - min_y) < min_curtain_height)
                    {
                      max_y = min_y + min_curtain_height;
                    }

                  paint_transparent_rectangle (widget,
                                               0,
                                               max_y,
                                               screen_width,
                                               (screen_height - max_y));

                  paint_transparent_rectangle (widget,
                                               0,
                                               0,
                                               screen_width, min_y);

                }
            }
        }
      if (min_x > 0)
        {

          paint_transparent_rectangle (widget,
                                       0,
                                       0,
                                       min_x,
                                       screen_height);

        }
      if (max_x < screen_width)
        {

          paint_transparent_rectangle (widget,
                                       max_x,
                                       0,
                                       (screen_width - max_x),
                                       screen_height);

        }
    }
  ungrab_pointer (gdk_display_get_default ());
  paint_curtain ();
  return TRUE;
}


